/*==========================================================================
 * 
 * HexEditorControl.java
 * 
 * $Author: randallco $
 * $Revision: 1.12 $
 * $Date: 2008/05/04 16:06:54 $
 * $Name:  $
 *
 * Created on 10-Nov-2003
 * Created by Marcel Palko alias Randallco (randallco@users.sourceforge.net) 
 *==========================================================================*/
package net.sourceforge.ehep.gui;

import java.util.Iterator;
import java.util.Stack;
import java.util.Vector;

import net.sourceforge.ehep.EhepPlugin;
import net.sourceforge.ehep.core.EHEP;
import net.sourceforge.ehep.core.Encoder;
import net.sourceforge.ehep.core.Utils;
import net.sourceforge.ehep.core.Watermarker;
import net.sourceforge.ehep.editors.HexEditor;
import net.sourceforge.ehep.events.CursorKeyListener;

import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.preference.PreferenceConverter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ControlEditor;
import org.eclipse.swt.custom.TableCursor;
import org.eclipse.swt.events.MenuAdapter;
import org.eclipse.swt.events.MenuEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;

/**
 * The main plug-in GUI control
 * 
 * @author Marcel Palko alias Randallco
 * @author randallco@users.sourceforge.net
 */
public class HexEditorControl {
	private final HexEditor hexEditor;
	private final Composite parent;
	private TableCursor cursor;
	private HexTable table;
	private Encoder encoder;
	private Watermarker watermarker;
	private WatermarkEditControl wmarkControl;
	private Vector<String> encodingTypes;
	private Vector<String> watermarkOptions;
	private Font font;
	private Combo encodingCombo;
	private Combo watermarkCombo;
	private Composite statusPanel;
	private Label statusOffset;
	private Label statusValue;
	private Label statusFileSize;
	private Point findResult;
	private int findResultSize;
	//private Button addWatermarkBtn;
	
	/**
	 * Creates an instance of a HexEditorControl embedded inside
	 * the supplied parent Composite.
	 * 
	 * @param parent the container of the example
	 * @param file the file descriptor
	 */
	public HexEditorControl(final HexEditor hexEditor, final Composite parent) {
		this.parent = parent;
		this.hexEditor = hexEditor;
		FontData fontData = PreferenceConverter.getFontData(EhepPlugin.getDefault().getPreferenceStore(), EHEP.PROPERTY_FONT);
		this.font = new Font(Display.getCurrent(), fontData);
		encoder = new Encoder(parent);
		watermarker = new Watermarker();
		this.wmarkControl = new WatermarkEditControl();
		
		//
		// Get list of supported encodings
		//
		encodingTypes = encoder.getEncodingTypes();
		
		//
		// Get list of options
		//
		watermarkOptions = watermarker.getWatermarkOptions();
		
		//
		// Define parent layout
		//
		GridLayout layout = new GridLayout();
		layout.numColumns = 1;
		layout.horizontalSpacing = 0;
		layout.verticalSpacing = 0;
		layout.marginWidth = 4;
		layout.marginHeight = 4;
		parent.setLayout(layout);
		
		//
		// Create main panel inside the parent panel
		//
		Composite mainPanel = new Composite(parent, SWT.NONE);
		layout = new GridLayout();
		layout.makeColumnsEqualWidth = true;
		layout.numColumns = 1;
		layout.horizontalSpacing = 0;
		layout.verticalSpacing = 4;
		layout.marginWidth = 0;
		layout.marginHeight = 0;
		mainPanel.setLayout(layout);
		mainPanel.setSize(mainPanel.computeSize(SWT.DEFAULT, SWT.DEFAULT));
		mainPanel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

		//
		// Create top panel inside the main panel
		//
		createTopPanel(mainPanel);

		//
		// Create data panel inside the main panel
		//
		createDataPanel(mainPanel);

		//
		// Create bottom panel inside the main panel
		//
		createBottomPanel(mainPanel);

		//
		// Resize the main panel
		//
		mainPanel.setSize(mainPanel.computeSize(SWT.DEFAULT, SWT.DEFAULT));
		mainPanel.layout();
	}
	
	/**
	 * We use two stacks to store undo & redo information 
	 */
	private Stack<IHexEditorCommand> undolist = new Stack<IHexEditorCommand>();
	private Stack<IHexEditorCommand> redolist = new Stack<IHexEditorCommand>();
	
	/** 
	 * Undo a command stored in undolist, and move this command 
	 * in redolist
	 */	
	public void undo(){
		if(undolist.empty())
			return;
		
		IHexEditorCommand comm;
		comm = (IHexEditorCommand)undolist.pop();
		comm.revoke();		
		redolist.push(comm);
		
		hexEditor.setDirty(true);
		updateStatusPanel();
		cursor.update();
	}

	/** 
	 * Redo a command stored in redolist, and move this command 
	 * in undolist
	 */
	public void redo(){
		if(redolist.empty())
			return;
		
		IHexEditorCommand comm;
		comm = (IHexEditorCommand)redolist.pop();
		comm.execute();		
		undolist.push(comm);
		
		hexEditor.setDirty(true);		
		updateStatusPanel();
		cursor.update();
	}
	
	/**
	 * Add a command to undolist, then redolist is cleared.
	 * undolist.size() will always be less than PROPERTY_MAX_UNDO_STEPS 
	 * @param comm
	 */
	private void addUndoStep(IHexEditorCommand comm){
		int maxundo = EhepPlugin.getDefault().getPreferenceStore().getInt(EHEP.PROPERTY_MAX_UNDO_STEPS);		

		undolist.push(comm);
		redolist.clear();
		
		if(maxundo>0 && undolist.size()>maxundo){
			undolist.remove(0);
		}
		
		hexEditor.setDirty(true);
	}

	interface IHexEditorCommand {
		void execute();
		void revoke();
	}
	
	/**
	 * Represents modification of a single byte
	 */
	class ModifyByteCommand implements IHexEditorCommand{
		private int row, col;
		private String text;
		
		ModifyByteCommand(int rowIndex, int columnIndex, String str){
			row = rowIndex;
			col = columnIndex;
			text = str;
			
			execute();
		}
		
		public void execute(){
			core();
			//
			//
			// Mark row that it was changed (marking just a changed cell is not possible - I didn't figured it out)
			//
			table.setCellBackground(row, col, EhepPlugin.getColor(PreferenceConverter.getColor(EhepPlugin.getDefault().getPreferenceStore(), EHEP.PROPERTY_COLOR_BACKGROUND_CHANGED_CELL)));
			table.setCellForeground(row, col, EhepPlugin.getColor(PreferenceConverter.getColor(EhepPlugin.getDefault().getPreferenceStore(), EHEP.PROPERTY_COLOR_FOREGROUND_CHANGED_CELL)));
		}
		
		/**
		 * 
		 */
		private void core() {
			String oldtext = table.getItem(row).getText(col);
			table.getItem(row).setText(col, text);
			text = oldtext;
			
			table.refreshCharacterView(row);
			table.refreshOffsetColumn();
		}

		//
		//Just the same as execute()
		//
		public void revoke(){
			core();
			//
			//
			// Mark row that it was changed (marking just a changed cell is not possible - I didn't figured it out)
			//
			table.setCellBackground(row, col, EhepPlugin.getColor(PreferenceConverter.getColor(EhepPlugin.getDefault().getPreferenceStore(), EHEP.PROPERTY_COLOR_BACKGROUND_UNDO)));
			table.setCellForeground(row, col, EhepPlugin.getColor(PreferenceConverter.getColor(EhepPlugin.getDefault().getPreferenceStore(), EHEP.PROPERTY_COLOR_FOREGROUND_UNDO)));
			table.select(row);
		}
	}
	
	public void modifyByte(int rowIndex, int columnIndex, String str){
		addUndoStep(new ModifyByteCommand(rowIndex, columnIndex, str));
	}
	
	/** 
	 * Reprensents the delete commands
	 */
	class DeleteCommand implements IHexEditorCommand{
		private int size, row, col;
		private HexTableBuffer buffer;
		
		private void backupData(int rowIndex, int columnIndex, int size){
			HexTablePointer p1 = new HexTablePointer(row, col);
			HexTablePointer p2 = new HexTablePointer(row, col).move(size-1);
			
			buffer = new HexTableBuffer(table);
			buffer.storeTableRegion(p1,p2);
		}
		
		DeleteCommand(int rowIndex, int columnIndex, int delSize){
			size = delSize;
			row = rowIndex;
			col = columnIndex;
			
			int tableSizeFromCursor = table.getTableSize(rowIndex, columnIndex);
			if (delSize == -1 || tableSizeFromCursor <= delSize)
				size = tableSizeFromCursor;
			
			execute();
		}
		
		public void execute(){
			backupData(row, col, size);
			
			table.deleteData(size, row, col, true);
		}
		
		public void revoke(){
			table.insertData(size, 0, row, col, true, null);
			buffer.restoreTableRegion(new HexTablePointer(row, col));
			table.setCellsBackground(row, col,size, EhepPlugin.getColor(PreferenceConverter.getColor(EhepPlugin.getDefault().getPreferenceStore(), EHEP.PROPERTY_COLOR_BACKGROUND_UNDO)));
			table.setCellsForeground(row, col,size, EhepPlugin.getColor(PreferenceConverter.getColor(EhepPlugin.getDefault().getPreferenceStore(), EHEP.PROPERTY_COLOR_FOREGROUND_UNDO)));
			table.select(row);
		}
	}
	
	public void delete(int rowIndex, int columnIndex, int size){
		addUndoStep(new DeleteCommand(rowIndex, columnIndex, size));
	}
	
	/** 
	 * Reprensents the insert commands
	 */
	class InsertDataCommand implements IHexEditorCommand{
		private int size, row, col, value;
		boolean refreshview;
	
		InsertDataCommand(int dataSize, int dataValue, int rowIndex, int columnIndex, boolean refresh){
			size = dataSize;
			row = rowIndex;
			col = columnIndex;
			value = dataValue;
			refreshview = refresh;
			
			execute();
		}
		
		public void execute(){
			table.insertData(size, value, row, col, refreshview, null);
			
			table.setCellsBackground(row, col,size, EhepPlugin.getColor(PreferenceConverter.getColor(EhepPlugin.getDefault().getPreferenceStore(), EHEP.PROPERTY_COLOR_BACKGROUND_INSERTED_CELL)));
			table.setCellsForeground(row, col,size, EhepPlugin.getColor(PreferenceConverter.getColor(EhepPlugin.getDefault().getPreferenceStore(), EHEP.PROPERTY_COLOR_FOREGROUND_INSERTED_CELL)));			
		}
		
		public void revoke(){
			table.deleteData(size, row, col, refreshview);
			table.select(row);
		}
	}
	
	public void insertData(int dataSize, int dataValue, int rowIndex, int columnIndex, boolean refresh){
		addUndoStep(new InsertDataCommand(dataSize, dataValue, rowIndex, columnIndex, refresh));
	}
	
	/** 
	 * Reprensents the append data command
	 */
	class AppendDataCommand implements IHexEditorCommand{
		private int size, row, col, value;
		boolean refreshview;
	
		AppendDataCommand(int dataSize, int dataValue, int rowIndex, int columnIndex, boolean refresh){
			size = dataSize;
			row = rowIndex;
			col = columnIndex;
			value = dataValue;
			refreshview = refresh;

			//If a file with length of '0' are editing, 
			//we should set ``col'' to 0, or ``undo'' will be incorrect
			int lines = table.getItemCount();
			int cols = table.getItem(lines-1).getItemSize();
			if(cols == 0) col = 0;
			
			execute();
		}
		
		public void execute(){
			table.appendData(size, value, row, col, refreshview);
			
			table.setCellsBackground(row, col,size, EhepPlugin.getColor(PreferenceConverter.getColor(EhepPlugin.getDefault().getPreferenceStore(), EHEP.PROPERTY_COLOR_BACKGROUND_INSERTED_CELL)));
			table.setCellsForeground(row, col,size, EhepPlugin.getColor(PreferenceConverter.getColor(EhepPlugin.getDefault().getPreferenceStore(), EHEP.PROPERTY_COLOR_FOREGROUND_INSERTED_CELL)));			
		}
		
		public void revoke(){			
			table.deleteData(size, row, col, refreshview);
			table.select(row);
		}
	}
	
	public void appendData(int dataSize, int dataValue, int rowIndex, int columnIndex, boolean refresh){
		addUndoStep(new AppendDataCommand(dataSize, dataValue, rowIndex, columnIndex, refresh));
	}

//	/**
//	 * Created by: Sophia Ghins
//	 * method to add watermark (signature)to the current open file
//	 * (currenty adds one cell (with ASCII value 'C') to the end of the file)
//	 * Date: 04/28/09
//	 */
//	public void addWatermark(){
//		int size, row, col, value;
//		boolean refreshview;
//		
//		row = table.getItemCount();
//		col = table.getItem(row-1).getItemSize();
//		size = 1;
//		value = 67;
//		refreshview = true;
//		
//		//table.appendData(size, value, row - 1, col, refreshview);
//		//table.setCellsBackground(row, col,size, EhepPlugin.getColor(PreferenceConverter.getColor(EhepPlugin.getDefault().getPreferenceStore(), EHEP.PROPERTY_COLOR_BACKGROUND_INSERTED_CELL)));
//		//table.setCellsForeground(row, col,size, EhepPlugin.getColor(PreferenceConverter.getColor(EhepPlugin.getDefault().getPreferenceStore(), EHEP.PROPERTY_COLOR_FOREGROUND_INSERTED_CELL)));
//		
//		appendData(size, value, row - 1, col, refreshview);
//		
//	}
	
	/**
	 * Created by: Sophia Ghins
	 * method to add watermark (signature)to the current open file
	 * adds with ASCII 'SIGN' to the end of the file
	 * Date: 05/13/09
	 */
	public void addWatermark(){
		int size, row, col, value;
		boolean refreshview;
		
		row = table.getItemCount();
		col = table.getItem(row-1).getItemSize();
//		if(col == 16){
//			row++;
//		}
		size = 1;
//		size = 4;
		refreshview = true;
		Iterator<String> it = watermarker.getWatermark_Sign().iterator();
		while(it.hasNext()){
			char val = it.next().charAt(0);
			value = val;
			appendData(size, value, row - 1, col, refreshview);
			row = table.getItemCount();
			col = table.getItem(row-1).getItemSize();
		}
		
	}
	
	
	/**
	 * Created by: Sophia Ghins
	 * method to remove watermark (signature)from the current open file
	 * (currently just removes the last cell from the table)
	 * Date: 04/28/09
	 */
	public void deleteWatermark(){
		int size, row, col, value;
		boolean refreshview, verify;
		
		row = table.getItemCount();
		col = table.getItem(row-1).getItemSize();
		size = 1;
		//value = 67;
		refreshview = true;
		
		//if(verifyWatermark()){
			delete(row - 1, col - 1, size);
		//}else{
			//sorry no watermark signature found
		//}
		//table.appendData(size, value, row - 1, col, refreshview);
		//table.setCellsBackground(row, col,size, EhepPlugin.getColor(PreferenceConverter.getColor(EhepPlugin.getDefault().getPreferenceStore(), EHEP.PROPERTY_COLOR_BACKGROUND_INSERTED_CELL)));
		//table.setCellsForeground(row, col,size, EhepPlugin.getColor(PreferenceConverter.getColor(EhepPlugin.getDefault().getPreferenceStore(), EHEP.PROPERTY_COLOR_FOREGROUND_INSERTED_CELL)));
						
	}
	
	/**
	 * Created by: Sophia Ghins
	 * method to verify that a file has been watermarked (already has signature)
	 * (currenty verifying that the last cell in the hex table is equal to ASCII value 'C')
	 * Date: 05/04/09
	 */
	public boolean verifyWatermark(){
		int row, col;
		String data;
		boolean chk;
				
		data = "C";
		row = table.getItemCount();
		col = table.getItem(row-1).getItemSize();
		chk = table.verifyData(data, row - 1);
//		TODO: compare the value of this item with value while debugging		
		if(chk){
			System.out.println("Success");
			return true;
		}
		return false;
	}

	/**
	 * Modified by: Sophia Ghins Date: 04/27/09
	 * Creates a combo box with all supported types
	 * @param parent
	 * @return Combo 
	 */
	private Combo getListingCombo(Composite parent, Vector<String> listTypes) {
		Combo genericCombo = new Combo(parent, SWT.SINGLE | SWT.BORDER | SWT.READ_ONLY);
		
		for (int i = 0; i < listTypes.size(); i++) {
			genericCombo.add(listTypes.get(i));
		} // for
		
		genericCombo.select(0);
		return genericCombo;
	}
	
//	/**
//	 * Creates a combo box with all supported encoding types
//	 * @param parent
//	 * @return Combo 
//	 */
//	private Combo getEncodingCombo(Composite parent, Vector<String> encodingTypes) {
//		Combo encodingCombo = new Combo(parent, SWT.SINGLE | SWT.BORDER | SWT.READ_ONLY);
//		
//		for (int i = 0; i < encodingTypes.size(); i++) {
//			encodingCombo.add(encodingTypes.get(i));
//		} // for
//		
//		encodingCombo.select(0);
//		return encodingCombo;
//	}
	
	/**
	 * Returns table
	 * @return table
	 */
	public HexTable getHexTable() {
		return table;
	}
	
	/**
	 * Returns default encoding
	 * @return String default encoding
	 */
	public String getDefaultEncoding() {
		return encodingTypes.get(0);
	}
	
	/**
	 * Returns current encoding
	 * @return current encoding (String)
	 */
	public String getCurrentEncoding() {
		int selectedEncoding = encodingCombo.getSelectionIndex();
		return (selectedEncoding >= 0) ? encodingCombo.getItem(selectedEncoding) : getDefaultEncoding();
	}

	private void encodingChanged() {
		int selection = encodingCombo.getSelectionIndex();
		if (selection == -1) return;
		String encoding = encodingTypes.get(selection);
		if (table.refreshCharacterView(encoding)) {
			//
			// If no error, set the last column title - encoding canonical name
			//
			table.getColumn(EHEP.TABLE_NUM_COLUMNS-1).setText(encoding);
		} // if
	}

	/**
	 * @author Sophia Ghins
	 * Action performed when watermark options are changed.
	 * Date: 04/27/09
	 */
	private void watermarkOptChanged(final Composite parent) {
		int selection = watermarkCombo.getSelectionIndex();
		if (selection == -1) return;
		String opt = watermarkOptions.get(selection);
		if(opt.equals("ADD")){
			if(MessageDialog.openQuestion(parent.getShell(), EHEP.ADD_WATERMARK_CONFIRM_HEADER, EHEP.ADD_WATERMARK_CONFIRM_MSG)){
				//if(hexEditor.isDirty()){
				//	MessageDialog.openInformation(parent.getShell(),"File modified", "File must be saved before watermark is added.");
				if(hexEditor.isReadOnly()){
					MessageDialog.openInformation(parent.getShell(),"Read Only","Sorry, This file is read-only! Cannot be modified.");
				}else{
//					addWatermark();
					int isOk = wmarkControl.addWatermark(this);
					if(isOk > 0){
						hexEditor.setDirty(true);
						updateStatusPanel();
						MessageDialog.openInformation(parent.getShell(),"SUCCESS","Successfully watermarked this file.");
					//TODO: ask user whether he would like to save the changes
					}else if(isOk == -2){
						MessageDialog.openInformation(parent.getShell(),"FILE SIZE","Sorry, the file is too small to be watermarked.");
					}else{
						MessageDialog.openInformation(parent.getShell(),"ERROR","Sorry unable to read file.");
					}
				}
			}
		}else if(opt.equals("REMOVE")){
			if(MessageDialog.openQuestion(parent.getShell(), EHEP.REMOVE_WATERMARK_CONFIRM_HEADER, EHEP.REMOVE_WATERMARK_CONFIRM_MSG)){
				if(hexEditor.isReadOnly()){
					MessageDialog.openInformation(parent.getShell(),"Read Only","Sorry, This file is read-only! Cannot be modified.");
				}else{
//					deleteWatermark();
					int isOk = wmarkControl.deleteWatermark(this);
					if(isOk > 0){
						hexEditor.setDirty(true);
						updateStatusPanel();
						MessageDialog.openInformation(parent.getShell(),"SUCCESS","Successfully REMOVED signature from the file.");
						//TODO: ask user whether he would like to save the changes
					}else{
						MessageDialog.openInformation(parent.getShell(),"ERROR","Unable to REMOVE signature from the file.");
					}
				}
			}	
		}else if(opt.equals("VERIFY")){
			if(wmarkControl.verifyWatermark()){
				MessageDialog.openInformation(parent.getShell(),"VERIFY","This file has a watermark signature.");
			}else{
				MessageDialog.openInformation(parent.getShell(),"VERIFY","Sorry, No watermarking found.");
			}
		}
	}	
	

	/**
	 * Grabs input focus.
	 */
	public void setFocus() {
		table.setFocus();
		table.select(0);
	}

	/**
	 * Disposes of all resources associated with a particular
	 * instance of the HexEditorControl.
	 */	
	public void dispose() {
		if (table != null) {
			table.dispose();
			table = null;
		}
		
		if (cursor != null) {
			cursor.dispose();
			cursor = null;
		}
		
		if (font != null) {
			font.dispose();
			font = null;
		}
		
		encodingTypes = null;
	}

	/**
	 * Creates top panel
	 * @param parent reference to a parent component
	 */
	private void createTopPanel(final Composite parent) {
		//
		// Create top panel
		//
		Composite topPanel = new Composite(parent, SWT.NONE);
		topPanel.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING));
		GridLayout layout = new GridLayout();
		layout.numColumns = 2;
		layout.horizontalSpacing = 10;
		layout.verticalSpacing = 0;
		layout.marginWidth = 4;
		layout.marginHeight = 0;
		topPanel.setLayout(layout);

		//
		// Create a panel with encoding selector
		//
		createEncodingPanel(topPanel, encodingTypes);		
		//createSearchPanel(topPanel);
		
		//
		// Create a panel to select watermark option
		//
		createWatermarkPanel(topPanel, watermarkOptions);
		/*
		//add watermark button to the top panel
		addWatermarkBtn = new Button(topPanel,SWT.PUSH);
		addWatermarkBtn.setVisible(true);
		addWatermarkBtn.setText("Add Watermark");
		addWatermarkBtn.addSelectionListener(new SelectionAdapter(){
			public void widgetSelected(SelectionEvent e) {
				MessageDialog.openQuestion(parent.getShell(), EHEP.ADD_WATERMARK_CONFIRM_HEADER, EHEP.ADD_WATERMARK_CONFIRM_MSG);
			}
		});
		*/		
		
	}
	
	class SearchOption{
		public final static boolean hexmode = true;
		public final static boolean textmode = false;
		public boolean mode;

		public static final boolean forward = true;
		public static final boolean backward = true;
		public boolean direction;
		
		public String text;
	}

	/**
	 * 
	 */
	protected void search() {
	}

	/**
	 * Creates a panel with encoding selector
	 * @param parent reference to a parent component
	 * @param encodingTypes vector with all supported encoding types
	 */
	private void createEncodingPanel(final Composite parent, final Vector<String> encodingTypes) {
		//
		// Create panel
		//
		Composite encodingPanel = new Composite(parent, SWT.NONE);
		encodingPanel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
		GridLayout layout = new GridLayout();
		layout.numColumns = 2;
		layout.horizontalSpacing = 5;
		layout.verticalSpacing = 0;
		layout.marginWidth = 0;
		layout.marginHeight = 0;
		encodingPanel.setLayout(layout);

		//
		// Create label
		//
		new Label(encodingPanel, SWT.NONE).setText("Encoding:");

		//
		// Create combo
		//
		encodingCombo = getListingCombo(encodingPanel, encodingTypes);

		//
		// Add selection listener to the combo box
		//
		encodingCombo.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				encodingChanged();
			} // widgetSelected()
		});
	}

	/**
	 * Created by: Sophia Ghins
	 * Date: 04/27/09
	 * Creates a panel with watermark selector
	 * @param parent reference to a parent component
	 * @param watermarkOptions vector with all supported encoding types
	 */
	private void createWatermarkPanel(final Composite parent, final Vector<String> watermarkOptions) {
		//
		// Create panel
		//
		Composite watermarkPanel = new Composite(parent, SWT.RIGHT);
		watermarkPanel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
		GridLayout layout = new GridLayout();
		layout.numColumns = 2;
		layout.horizontalSpacing = 5;
		layout.verticalSpacing = 0;
		layout.marginWidth = 25;
		layout.marginHeight = 0;
		//layout.marginLeft = 10;
		watermarkPanel.setLayout(layout);

		//
		// Create label
		//
		new Label(watermarkPanel, SWT.NONE).setText("Watermark:");
		
		//
		// Create combo
		//
		watermarkCombo = getListingCombo(watermarkPanel, watermarkOptions);
		
		//
		// Add selection listener to the combo box
		//
		watermarkCombo.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				table.setBufSize(0);
				table.insertTableDataInBuf();
				wmarkControl.getBufManager().setCurrFileBufSize(table.getBufSize());
				watermarkOptChanged(parent);
			} 
		});
		
	}		
	
	
	/**
	 * Creates a data panel
	 * @param parent reference to a parent component
	 */
	private void createDataPanel(final Composite parent) {
		//
		// Create data panel
		//
		Composite dataPanel = new Composite(parent, SWT.NONE);
		GridLayout layout = new GridLayout();
		layout.numColumns = 1;
		layout.horizontalSpacing = 0;
		layout.verticalSpacing = 0;
		layout.marginWidth = 0;
		layout.marginHeight = 0;
		dataPanel.setLayout(layout);
		dataPanel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

		//
		// Create a table panel
		//
		createTablePanel(dataPanel);
	}

	/**
	 * Creates a table panel
	 * @param parent reference to a parent component
	 */
	private void createTablePanel(final Composite parent) {
		//
		// Create context (popup) menu
		//
		Menu menu = createPopupMenu();

		//
		// Create table panel
		//
		Composite tablePanel = new Composite(parent, SWT.NONE);
		GridLayout layout = new GridLayout();
		layout.numColumns = 1;
		layout.horizontalSpacing = 0;
		layout.verticalSpacing = 0;
		layout.marginWidth = 0;
		layout.marginHeight = 0;
		tablePanel.setLayout(layout);
		tablePanel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

		//
		// Create table
		//
		table = new HexTable(tablePanel, this, SWT.VIRTUAL | SWT.V_SCROLL | SWT.BORDER | SWT.SINGLE);
		table.setHeaderVisible(true);
		table.setLinesVisible(true);
		table.setFont(font);
		table.setBackground(EhepPlugin.getColor(PreferenceConverter.getColor(EhepPlugin.getDefault().getPreferenceStore(), EHEP.PROPERTY_COLOR_BACKGROUND_TABLE)));
		table.setForeground(EhepPlugin.getColor(PreferenceConverter.getColor(EhepPlugin.getDefault().getPreferenceStore(), EHEP.PROPERTY_COLOR_FOREGROUND_TABLE)));
		table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
		table.setData(encodingTypes);
		table.setMenu(menu);

		//
		// Create table cursor
		//
		cursor = new TableCursor(table.getTable(), SWT.NONE);
		cursor.setFont(font);
		cursor.setMenu(menu);

		//
		// Create an editor to edit the cell when the user hits 0..9 or A..F key 
		// while over a cell in the table
		//
		final ControlEditor editor = new ControlEditor(cursor);
		editor.grabHorizontal = true;
		editor.grabVertical = true;

		//
		// Add some cursor listeners
		//
		addCursorListeners(cursor, editor);

		//
		// Create table header
		//
		createTableHeader(table);
	}

	/**
	 * Creates bottom panel
	 * @param parent reference to a parent component
	 */
	private void createBottomPanel(final Composite parent) {
		//
		// Create bottom panel
		//
		Composite bottomPanel = new Composite(parent, SWT.NONE);
		bottomPanel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
		GridLayout layout = new GridLayout();
		layout.numColumns = 2;
		layout.horizontalSpacing = 10;
		layout.verticalSpacing = 0;
		layout.marginWidth = 4;
		layout.marginHeight = 0;
		bottomPanel.setLayout(layout);

		//
		// Create and add a status panel
		//
		createStatusPanel(bottomPanel);
	}

	/**
	 * Creates a status panel
	 * @param parent reference to a parent component
	 */
	private void createStatusPanel(final Composite parent) {
		//
		// Create status panel
		//
		statusPanel = new Composite(parent, SWT.NONE);
		statusPanel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
		GridLayout layout = new GridLayout();
		layout.numColumns = 3;
		layout.horizontalSpacing = 5;
		layout.verticalSpacing = 0;
		layout.marginWidth = 0;
		layout.marginHeight = 0;
		statusPanel.setLayout(layout);

		//
		// Create status sub-panels
		//
		createOffsetPanel(statusPanel);
		createValuePanel(statusPanel);
		createFileSizePanel(statusPanel);
		//createDummyPanel(statusPanel);
		//createDummyPanel(statusPanel);
	}

	private void createOffsetPanel(Composite parent) {
		//
		// Offset panel
		//
		Composite offsetPanel = new Composite(parent, SWT.NONE);
		offsetPanel.setLayoutData(new GridData(GridData.FILL_BOTH));
		GridLayout layout = new GridLayout();
		layout.numColumns = 1;
		layout.horizontalSpacing = 5;
		layout.verticalSpacing = 0;
		layout.marginWidth = 0;
		layout.marginHeight = 0;
		offsetPanel.setLayout(layout);
		
		statusOffset = new Label(offsetPanel, SWT.BORDER);
		statusOffset.setText(" Offset: 00000000h of 00000000h (100%)  ");
		GridData gridData = new GridData(GridData.FILL_BOTH);
		statusOffset.setLayoutData(gridData);
	}

	private void createValuePanel(Composite parent) {
		//
		// Value panel
		//
		Composite valuePanel = new Composite(parent, SWT.NONE);
		valuePanel.setLayoutData(new GridData(GridData.FILL_BOTH));
		GridLayout layout = new GridLayout();
		layout.numColumns = 1;
		layout.horizontalSpacing = 5;
		layout.verticalSpacing = 0;
		layout.marginWidth = 0;
		layout.marginHeight = 0;
		valuePanel.setLayout(layout);
		
		statusValue = new Label(valuePanel, SWT.BORDER);
		statusValue.setText(" Value: 0xFF (hex) = 234 (dec) = 0234 (oct) = 0101101011010011 (bin) ");
		GridData gridData = new GridData(GridData.FILL_BOTH);
		statusValue.setLayoutData(gridData);
	}

	private void createFileSizePanel(Composite parent) {
		//
		// FileSize panel
		//
		Composite fileSizePanel = new Composite(parent, SWT.NONE);
		fileSizePanel.setLayoutData(new GridData(GridData.FILL_BOTH));
		GridLayout layout = new GridLayout();
		layout.numColumns = 1;
		layout.horizontalSpacing = 5;
		layout.verticalSpacing = 0;
		layout.marginWidth = 0;
		layout.marginHeight = 0;
		fileSizePanel.setLayout(layout);
		
		statusFileSize = new Label(fileSizePanel, SWT.BORDER);
		statusFileSize.setText(" Filesize: 10000000 bytes ");
		GridData gridData = new GridData(GridData.FILL_BOTH);
		statusFileSize.setLayoutData(gridData);
	}

	/**
	 * Adds some cursor listeners
	 * @param cursor table cursor
	 * @param editor table editor
	 */
	private void addCursorListeners(final TableCursor cursor, final ControlEditor editor) {
		//
		// Add key listener
		//
		final CursorKeyListener cursorKeyListener = new CursorKeyListener(this, hexEditor, cursor, editor);
		
		cursor.addKeyListener(cursorKeyListener);

		//
		// Add selection listener
		//
		cursor.addSelectionListener(new SelectionAdapter() {
			//
			// When the TableEditor is over a cell, select the corresponding row in the table
			//
			public void widgetSelected(SelectionEvent e) {
				table.setSelection(new TableItem[] {cursor.getRow()});
				
				updateStatusPanel();

				if (cursorKeyListener.getText() == null) {
					//
					// Text component was already disposed - do nothing here...
					//
					return;
				} // if
				
				//
				// If there is still opened a cell editor, close it at the position where it was opened
				//
				cursorKeyListener.getCellEditorKeyListener().closeCellEditor(cursorKeyListener.getEventItem(), cursorKeyListener.getEventColumn(), "0" + cursorKeyListener.getText().getText().toUpperCase());
			}

			//
			// When the user hits "ENTER" in the TableCursor, pop up a text editor so that 
			// they can change the text of the cell
			//
			public void widgetDefaultSelected(SelectionEvent e) {
				table.setSelection(new TableItem[] {cursor.getRow()});
			}
		});
	}

	/**
	 * Creates table header
	 * @param table data table
	 */
	private void createTableHeader(final HexTable table) {
		for (int i = 0; i < EHEP.TABLE_NUM_COLUMNS; i++) {
			TableColumn tableColumn = new TableColumn(table.getTable(), SWT.CENTER);
			tableColumn.setResizable(true);
			if (i == 0) {
				tableColumn.setText("Offset");
			} else if (i >= 1 && i <= EHEP.TABLE_NUM_DATA_COLUMNS) {
				tableColumn.setText(Integer.toHexString(i-1).toUpperCase());
			}
			else {
				tableColumn.setText("ASCII");
			}
		} // for
	}

	public TableCursor getCursor() {
		return cursor;
	}
	
	public Point getPosition() {
		return new Point(cursor.getColumn(), table.getTable().indexOf(cursor.getRow()));
	}
	
	/** 
	 * Creates all items located in the popup menu and associates
	 * all the menu items with their appropriate functions.
	 *
	 * @return	Menu The created popup menu.
	 */
	private Menu createPopupMenu() {
		Menu popUpMenu = new Menu(parent.getShell(), SWT.POP_UP);

		/** 
		 * Adds a listener to handle enabling and disabling 
		 * some items in the Edit submenu.
		 */
		popUpMenu.addMenuListener(new MenuAdapter() {
			public void menuShown(MenuEvent e) {
				Menu menu = (Menu) e.widget;
				MenuItem[] items = menu.getItems();
				int rowIndex = table.getSelectionIndex();
				int columnIndex = cursor.getColumn();
				TableItem item = cursor.getRow();
				int tableSize = table.getTableSize();
				HexTablePointer p1 = new HexTablePointer(rowIndex, columnIndex-1);
				HexTablePointer p2 = new HexTablePointer(0,0).move(tableSize-1);
				HexTablePointer p3 = new HexTablePointer(0,0);
				
				boolean b1 = (columnIndex != 0);
				boolean b2 = (columnIndex != EHEP.TABLE_NUM_COLUMNS-1);
				boolean b3 = item.getText(columnIndex).equals(EHEP.TABLE_EMPTY_CELL);
				boolean b4 = p1.equals(p2);
				boolean b5 = p1.equals(p3);
				boolean b6 = hexEditor.isReadOnly();
				
				boolean enableInsert = b1 && b2 && !b3 && !b6;
				boolean enableDelete = b1 && b2 && !b3 && !b6;
				boolean enableAppend = ((b1 && b2 && !b3 && b4) || (b3 && b5)) && !b6;
				
				items[0].setEnabled(enableInsert); // insert
				items[1].setEnabled(enableAppend); // append
				//--- separator ---
				items[3].setEnabled(enableDelete); // delete
				// --- separator ---
				items[5].setEnabled(true);        // goto
				// --- separator ---
				items[7].setEnabled(true);        // about
			} // menuShown()
		});


		//
		// "Insert" menu item
		//
		MenuItem item = new MenuItem(popUpMenu, SWT.PUSH/*SWT.CASCADE*/);
		item.setText("Insert...");
		item.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				popupMenuInsertData(table.getSelectionIndex(), cursor.getColumn());
			}
		});
	
		//
		// "Append" menu item
		//
		item = new MenuItem(popUpMenu, SWT.PUSH/*SWT.CASCADE*/);
		item.setText("Append...");
		item.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				popupMenuAppendData(table.getSelectionIndex(), cursor.getColumn());
			}
		});

		//
		// Separator
		//
		new MenuItem(popUpMenu, SWT.SEPARATOR);
		
		//
		// "Undo" and "Redo" menu item
		//
		item = new MenuItem(popUpMenu, SWT.PUSH/*SWT.CASCADE*/);
		item.setText("Undo");
		item.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				undo();
			}
		});		
		
		item = new MenuItem(popUpMenu, SWT.PUSH/*SWT.CASCADE*/);
		item.setText("Redo");
		item.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				redo();
			}
		});		
		//
		// Separator
		//
		new MenuItem(popUpMenu, SWT.SEPARATOR);	

		//
		// "Delete" menu item
		//
		item = new MenuItem(popUpMenu, SWT.PUSH/*SWT.CASCADE*/);
		item.setText("Delete...");
		item.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				popupMenuDeleteData(table.getSelectionIndex(), cursor.getColumn());
			}
		});

		//
		// Separator
		//
		new MenuItem(popUpMenu, SWT.SEPARATOR);	

		//
		// "Goto..." menu item
		//
		item = new MenuItem(popUpMenu, SWT.PUSH/*SWT.CASCADE*/);
		item.setText("Goto...");
		item.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				popupMenuGoto(table.getSelectionIndex(), cursor.getColumn());
			}
		});

		//
		// Separator
		//
		new MenuItem(popUpMenu, SWT.SEPARATOR);	
	
		//
		// "About" menu item
		//
		item = new MenuItem(popUpMenu, SWT.PUSH/*SWT.NULL*/);
		item.setText("About...");
		item.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				popupMenuAbout();
			}
		});

		return popUpMenu;
	}

	/**
	 * Inserts new data (invoked from popup menu)
	 * @param rowIndex
	 * @param columnIndex
	 */
	private void popupMenuInsertData(int rowIndex, int columnIndex) {
		//
		// Display the dialog
		//
		AddDataDialog addDataDialog = new AddDataDialog(parent.getShell(), SWT.APPLICATION_MODAL | SWT.DIALOG_TRIM, EHEP.DIALOG_TYPE_INSERT);
		addDataDialog.setText("Insert data");
		int[] addDialogResult = addDataDialog.open();
		
		if (addDialogResult == null) {
			//
			// Cancel button pressed - do nothing
			//
			return;
		}
		
		//
		// Retrieve the parameters from the 'Insert' dialog
		//
		int dataSize = addDialogResult[0];
		int dataValue = addDialogResult[1];
		
		if (dataSize <= 0) return;
		
		//
		// Insert new bytes into the table
		//
		insertData(dataSize, dataValue, rowIndex, columnIndex-1, true);

		//
		// Set "dirty" flag
		//
		hexEditor.setDirty(true);

		//
		// Update the status panel
		//
		updateStatusPanel();
	}

	/**
	 * Appends new data (invoked from popup menu)
	 * @param rowIndex
	 * @param columnIndex
	 */
	private void popupMenuAppendData(int rowIndex, int columnIndex) {
		//
		// Display the dialog
		//
		AddDataDialog addDataDialog = new AddDataDialog(parent.getShell(), SWT.APPLICATION_MODAL | SWT.DIALOG_TRIM, EHEP.DIALOG_TYPE_APPEND);
		addDataDialog.setText("Append data");
		int[] addDialogResult = addDataDialog.open();
		
		if (addDialogResult == null) {
			//
			// Cancel button pressed - do nothing
			//
			return;
		}
		
		//
		// Retrieve the parameters from the 'Insert' dialog
		//
		int dataSize = addDialogResult[0];
		int dataValue = addDialogResult[1];
		
		if (dataSize <= 0) return;
		
		//
		// Append new bytes into the table
		//
		appendData(dataSize, dataValue, rowIndex, columnIndex, true);

		//
		// Set "dirty" flag
		//
		hexEditor.setDirty(true);

		//
		// Update the status panel
		//
		updateStatusPanel();
	}

	/**
	 * Deletes data from the table (invoked from popup menu)
	 * @param rowIndex
	 * @param columnIndex
	 */
	private void popupMenuDeleteData(int rowIndex, int columnIndex) {
		//
		// Display the dialog
		//
		DeleteDataDialog deleteDataDialog = new DeleteDataDialog(parent.getShell(), SWT.APPLICATION_MODAL | SWT.DIALOG_TRIM);
		deleteDataDialog.setText("Delete data");
		int delSize = deleteDataDialog.open();
		
		if (delSize == 0) {
			//
			// Cancel button pressed - do nothing
			//
			return;
		}
		
		//
		// Delete data from the table
		// table.deleteData(delSize, rowIndex, columnIndex-1, true);
		delete(rowIndex, columnIndex-1, delSize);

		//
		// Set "dirty" flag
		//
		hexEditor.setDirty(true);
		
		//
		// Update the status panel
		//
		updateStatusPanel();
	}

	/**
	 * Displays the 'Goto...' dialog
	 */
	private void popupMenuGoto(int rowIndex, int columnIndex) {
		//
		// Display the dialog
		//
		GotoDialog gotoDialog = new GotoDialog(parent.getShell(), SWT.APPLICATION_MODAL | SWT.DIALOG_TRIM, rowIndex, columnIndex);
		HexTablePointer p = gotoDialog.open();
		
		if (p == null) {
			//
			// Error calculating new position - do nothing
			//
			return;
		} // if
		
		if (p.getRowIndex() < 0 || p.getColumnIndex() < 0) {
			MessageDialog.openError(parent.getShell(), EHEP.DIALOG_TITLE_ERROR, "Address is out of range!");
			cursor.setSelection(0, 1);
			cursor.redraw();
			table.setSelection(0);
			//
			// Update the status panel
			//
			updateStatusPanel();
			return;
		}
		
		try {
			cursor.setSelection(p.getRowIndex(), p.getColumnIndex()+1);
		}
		catch (IllegalArgumentException e) {
			int numRows = table.getItemCount();
			int lastRowIndex = (numRows > 0) ? (numRows-1) : numRows;
			MessageDialog.openError(parent.getShell(), EHEP.DIALOG_TITLE_ERROR, "Address is out of range!");
			cursor.setSelection(lastRowIndex, table.getItem(table.getItemCount()-1).getItemSize());
			cursor.redraw();
			table.setSelection(lastRowIndex);
			//
			// Update the status panel
			//
			updateStatusPanel();
			return;
		}
		
		//
		// Place the cursor where was calculated
		//
		cursor.setSelection(p.getRowIndex(), p.getColumnIndex()+1);
		cursor.redraw();
		table.setSelection(p.getRowIndex());

		//
		// Update the status panel
		//
		updateStatusPanel();
	}

	/**
	 * Displays the 'About' dialog
	 */
	private void popupMenuAbout() {
		//
		// Display the dialog
		//
		AboutDialog aboutDialog = new AboutDialog(parent.getShell(), SWT.APPLICATION_MODAL | SWT.DIALOG_TRIM);
		aboutDialog.open();
	}

	/**
	 * Updates the status panel
	 */
	public void updateStatusPanel() {
		table.redraw();
		cursor.redraw();
		int rowIndex = table.getSelectionIndex();
		int columnIndex = cursor.getColumn();
		
		if (rowIndex < 0 || columnIndex < 0 || columnIndex >= EHEP.TABLE_NUM_COLUMNS) {
			EhepPlugin.log("updateStatusPanel(): incorrect cursor coordinates!");
			return;
		}
		
		HexTableItem item = table.getItem(rowIndex);
		String cellData = item.getText(columnIndex);
		
		if (columnIndex < 1 || columnIndex > EHEP.TABLE_NUM_DATA_COLUMNS || cellData.length() == 0 || cellData.equals(EHEP.TABLE_EMPTY_CELL)) {
			//
			// Cursor is out of data cells - nothing to display
			//
			statusOffset.setText("");
			statusValue.setText("");
		} // if
		else {
			//
			// Cursor is above the data cell - update offset panel
			//
			HexTablePointer p = new HexTablePointer(rowIndex, columnIndex-1);
			int offset = p.getOffset();
			int tableSize = table.getTableSize();
			int ratio = (tableSize > 1) ? (100*offset/(tableSize-1)) : 100;
			statusOffset.setText(" Offset: " + Utils.zeroPadding(Integer.toHexString(offset).toUpperCase(), 8) + "h of " + Utils.zeroPadding(Integer.toHexString(tableSize-1).toUpperCase(), 8) + "h (" + ratio + "%) ");
			
			//
			// Update value panel
			//
			String value = item.getText(columnIndex);
			int number = Integer.parseInt(value, 16);

			String binString = Integer.toBinaryString(number);
			statusValue.setText(" Value: 0x" + value + " (hex) = " + number + " (dec) = 0" + Integer.toOctalString(number) + " (oct) = " + ("00000000".substring(binString.length()) + binString) + " (bin) ");
		} // else
		
		//
		// Update table/file size
		//
		statusFileSize.setText(" Filesize: " + table.getTableSize() + " bytes ");
	}


	public Point findAndSelect(Point location, String hexFindString, boolean searchForward, boolean caseSensitive) {

		int colNum = table.getTable().getColumnCount() - 1;
		int rowNum = table.getTable().getItemCount();

		if (location.equals(findResult))
			inc(location, rowNum, colNum);
		Point pos = new Point(location.x, location.y);
		select(findResult, findResultSize, EHEP.PROPERTY_COLOR_BACKGROUND_TABLE, EHEP.PROPERTY_COLOR_FOREGROUND_TABLE);
		findResult = null;

		String findString = hexFindString;
		while (true) {
			String s = table.getItem(pos.y).getText(pos.x % colNum);
			String cmp = findString.substring(0, 2);
			if (caseSensitive && s.equals(cmp) || !caseSensitive && Utils.toLoweCase(s).equals(Utils.toLoweCase(cmp))) {
				if (findResult == null)
					findResult = new Point(pos.x, pos.y);
				findString = findString.substring(2);
				if (findString.length() == 0) {
					findResultSize = (pos.x - findResult.x) + (pos.y - findResult.y) * (colNum - 1);
					select(findResult, findResultSize, EHEP.PROPERTY_COLOR_BACKGROUND_FIND_RESULT, EHEP.PROPERTY_COLOR_FOREGROUND_FIND_RESULT);
					table.getTable().select(findResult.y + table.getTable().getClientArea().height / table.getTable().getItemHeight() / 2);
					table.getTable().showSelection();
					table.getTable().select(findResult.y);
					cursor.setSelection(findResult.y, findResult.x);
					return pos;
				}
			} else {
				findString = hexFindString;
				findResult = null;
			}
			if (!inc(pos, rowNum, colNum))
				return null;
		}
	}

	private boolean inc(Point p, int rowNum, int colNum) {
		if (++p.x < colNum)
			return true;
		p.x = 1;
		return ++p.y < rowNum;
	}

	private void select(Point p, int size, String colorBgProperty, String colorFgProperty) {
		if (p == null)
			return;
		table.setCellsBackground(p.y, p.x - 1, size, EhepPlugin.getColor(PreferenceConverter.getColor(EhepPlugin.getDefault().getPreferenceStore(), colorBgProperty))); 
		table.setCellsForeground(p.y, p.x - 1, size, EhepPlugin.getColor(PreferenceConverter.getColor(EhepPlugin.getDefault().getPreferenceStore(), colorFgProperty))); 
	}
	
	/**
	 * Returns reference to watermarker object
	 * @author Sophia 
	 * Date: 06/20/09 
	 * @return watermarker
	 */
	public Watermarker getWatermarker(){
		return watermarker;
	}
	
	/**
	 * Returns reference to WatermarkEditControl object
	 * @author Sophia 
	 * Date: 06/20/09 
	 * @return watermarker
	 */
	public WatermarkEditControl getWatermarkEditControl(){
		return wmarkControl;
	}


}
